#include "./../inc/stack.h"

#include <string.h>
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

typedef struct _STACK
{
	int size;
	int capSize;
	int elememtSize;
	unsigned char *data;

	UFO_Stack handle;
}STACK;

void internal_stack_realloc(STACK *pStack)
{
	if (!pStack->data) {
		pStack->capSize = 32;
		pStack->data = malloc(pStack->capSize*pStack->elememtSize);
        memset(pStack->data, 0, pStack->capSize*pStack->elememtSize);
	}
	else {
		pStack->capSize = pStack->capSize<<2;
		pStack->data = realloc(pStack->data, pStack->capSize*pStack->elememtSize);
        memset(pStack->data+(pStack->capSize/2*pStack->elememtSize), 0, pStack->capSize/2*pStack->elememtSize);
	}
}

UFO_Stack ufoStackCreate(int elementSize)
{
	STACK *pStack = malloc(sizeof(STACK));
	memset(pStack, 0, sizeof(STACK));
	pStack->elememtSize = elementSize;
	pStack->handle = (UFO_Stack)ufoCreateHandle(UFO_ID_STACK, pStack);

	return pStack->handle;
}

int ufoStackPush(UFO_Stack _stack, void* element)
{
	STACK *pStack = ufoObjectFromHandle((UFO_Handle)_stack);
	if (pStack) {
		if (pStack->size >= pStack->capSize) {
			internal_stack_realloc(pStack);
		}

        memcpy(pStack->data+pStack->elememtSize*pStack->size, element, pStack->elememtSize);
        pStack->size++;
        
		return 1;
	}

	return 0;
}

void* ufoStackPop(UFO_Stack _stack)
{
	STACK *pStack = ufoObjectFromHandle((UFO_Handle)_stack);
	if (pStack) {
		if (pStack->size == 0)
			return 0;
		--pStack->size;
		return pStack->data + pStack->size*pStack->elememtSize;
	}
	return 0;
}

int ufoStackGetSize(UFO_Stack _stack)
{
	STACK *pStack = ufoObjectFromHandle((UFO_Handle)_stack);
	if (pStack) {
		return pStack->size;
	}
	return 0;
}

int ufoStackReSize(UFO_Stack _stack, int size)//### bug here, size
{
	STACK *pStack = ufoObjectFromHandle((UFO_Handle)_stack);
	if (pStack) {
		pStack->size = size;
        if (pStack->size >= pStack->capSize) {
			internal_stack_realloc(pStack);
		}
		return 1;
	}
	return 0;
}

void* ufoStackGetElement(UFO_Stack _stack, int index)
{
	STACK *pStack = (STACK*)ufoObjectFromHandle((UFO_Handle)_stack);
	if (pStack) {
		if (index <=  pStack->size)
			return pStack->data + index*pStack->elememtSize;
	}
	return 0;
}

void* ufoStackTop(UFO_Stack _stack)
{
	return ufoStackGetElement(_stack, ufoStackGetSize(_stack)-1);
}